﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GomTest.GenTalents
{
    static class TalentScriptWriter
    {
        public static void BuildTalentInfoScript(List<AdvancedClass> advancedClassList,
            Dictionary<string, TalentTree> talentTrees, Dictionary<string, Dictionary<string, TalentInfo>> talentLookup)
        {
            var outFilePath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "ClassTalentsData.cs");
            Console.WriteLine("Writing talent info to {0}", outFilePath);
            using (var fs = System.IO.File.Open(outFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            using (var writer = new System.IO.StreamWriter(fs))
            {
                writer.WriteLine("namespace Rage");
                writer.WriteLine("{");
                writer.WriteLine("    using System;");
                writer.WriteLine("    using System.Collections.Generic;");
                writer.WriteLine("    using System.Reflection;");
                writer.WriteLine("    using System.Text;");
                writer.WriteLine("");
                writer.WriteLine("    // This file is automatically generated by the Rage.TalentClassGenerator tool. Please don't edit it directly.");
                writer.WriteLine("");
                //writer.WriteLine("    // Imperial");
                //writer.WriteLine("    // Republic");

                var testtrees = talentTrees.ToList();
                foreach (var ac in advancedClassList)
                {
                int numTalentsInAllACsTrees = 0;
                var acTalentTrees = new Dictionary<string, TalentTree>();
                KeyValuePair<string, TalentTree> tree1t = new KeyValuePair<string, TalentTree>(),
                    tree2t = new KeyValuePair<string, TalentTree>(),
                    tree3t = new KeyValuePair<string, TalentTree>();
                while (testtrees.Count > 0)
                {
                    bool foundallthree = false;
                    for(int i=0; i < testtrees.Count; ) {
                        if (testtrees[i].Value.Id.Replace("_", ".").Contains(ac.Trees[0].Replace("_", "."))) {
                            tree1t = testtrees[i];
                            testtrees.RemoveAt(i);
                            numTalentsInAllACsTrees += tree1t.Value.Talents.Count;
                        } else if (testtrees[i].Value.Id.Replace("_", ".").Contains(ac.Trees[1].Replace("_", "."))) {
                            tree2t = testtrees[i];
                            testtrees.RemoveAt(i);
                            numTalentsInAllACsTrees += tree2t.Value.Talents.Count;
                        } else if (testtrees[i].Value.Id.Replace("_", ".").Contains(ac.Trees[2].Replace("_", "."))) {
                            tree3t = testtrees[i];
                            testtrees.RemoveAt(i);
                            numTalentsInAllACsTrees += tree3t.Value.Talents.Count;
                        } else { i++; }
                        if (tree1t.Key != null && tree2t.Key != null && tree3t.Key != null) { foundallthree = true; break; }
                    }
                    if (foundallthree) { break; }
                }
                if (tree1t.Key != null) { acTalentTrees.Add(tree1t.Key, tree1t.Value); }
                if (tree2t.Key != null) { acTalentTrees.Add(tree2t.Key, tree2t.Value); }
                if (tree3t.Key != null) { acTalentTrees.Add(tree3t.Key, tree3t.Value); }
                writer.WriteLine("    public partial class " + ac.Name + "Talents : TalentsBase");
                writer.WriteLine("    {");
                writer.WriteLine("        public override TalentsBase Clone()");
                writer.WriteLine("        {");
                writer.WriteLine("            " + ac.Name + "Talents clone = (" + ac.Name + "Talents)MemberwiseClone();");
                writer.WriteLine("            clone._data = (int[])_data.Clone();");
                writer.WriteLine("            clone.TreeCounts = new int[] { -1, -1, -1 };");
                writer.WriteLine("            return clone;");
                writer.WriteLine("        }");
                writer.WriteLine("    ");
                writer.WriteLine("        private int[] _data = new int[" + numTalentsInAllACsTrees + "];");
                writer.WriteLine("        public override int[] Data { get { return _data; } }");
                writer.WriteLine("        public " + ac.Name + "Talents() { }");
                writer.WriteLine("        public " + ac.Name + "Talents(string talents)");
                writer.WriteLine("        {");
                writer.WriteLine("            LoadString(talents);");
                writer.WriteLine("        }");
                writer.WriteLine("        public static string[] TreeNames = new[] {");
                string tree1 = ac.Trees[0].Split('_')[ac.Trees[0].Split('_').Count() - 1],
                       tree2 = ac.Trees[1].Split('_')[ac.Trees[1].Split('_').Count() - 1],
                       tree3 = ac.Trees[2].Split('_')[ac.Trees[2].Split('_').Count() - 1];
                tree1 = tree1[0].ToString().ToUpper() + tree1.Substring(1);
                tree2 = tree2[0].ToString().ToUpper() + tree2.Substring(1);
                tree3 = tree3[0].ToString().ToUpper() + tree3.Substring(1);
                writer.WriteLine("            @\"" + tree1 + "\",");
                writer.WriteLine("            @\"" + tree2 + "\",");
                writer.WriteLine("            @\"" + tree3 + "\",};");
                writer.WriteLine("    ");
                int[] treeTalentCounts = new int[] { 0, 0, 0 }; int currentTree = 0; int currentTalent = 0;
                int[] treeTalentCountsSaved = new int[] { 0, 0, 0 };
                foreach (var tree in acTalentTrees)
                {
                writer.WriteLine("        #region " + tree.Value.Name);
                treeTalentCountsSaved[currentTree] = treeTalentCounts[currentTree];
                writer.WriteLine("        public override int TreeStartingIndexes_" + currentTree + " { get { return " + treeTalentCountsSaved[currentTree] + "; } }");
                var talentIdToTalent = talentLookup[tree.Value.Id];
                foreach (var talent in talentIdToTalent.Values)
                {
                List<string> descs = new List<string>();
                for (int rank = 0; rank <= talent.MaxPoints; rank++)
                {
                    string desc = talent.Ability.Description.Trim();
                    if (!string.IsNullOrEmpty(talent.Ability.TalentTokens))
                    {
                        string tokens = talent.Ability.TalentTokens;
                        string[] values = { "", "", "", "", "", "", "" };
                        int count = 0;
                        while (tokens.Length > 0)
                        {
                            if (tokens.StartsWith("rank,")) {
                                tokens = tokens.Substring("rank,".Length);
                                values[count] = tokens.Substring(0, tokens.IndexOf('\''));
                                count++;
                            } else if (tokens.StartsWith("healing,")) {
                                tokens = tokens.Substring("healing,".Length);
                                values[count] = tokens.Substring(0, tokens.IndexOf(','));//IndexOf('\''));
                                count++;
                            /*} else if (tokens.StartsWith("damage,")) {
                                tokens = tokens.Substring("damage,".Length);
                                values[count] = tokens.Substring(0, tokens.IndexOf(','));//IndexOf('\''));
                                count++;*/
                            } else if (tokens.StartsWith("duration,")) {
                                tokens = tokens.Substring("duration,".Length);
                                values[count] = tokens.Substring(0, tokens.IndexOf('\''));
                                count++;
                            } else if (tokens.Length > 1) {
                                tokens = tokens.Substring(1);
                            } else { tokens = ""; }
                        }
                        for (int i = 0; i < values.Length; i++)
                        {
                            if (string.IsNullOrEmpty(values[i])) { continue; }
                            if (rank == 0) {
                                desc = desc.Replace(string.Format("<<{0}>>", i + 1), (double.Parse(values[i])).ToString() + "*Pts");
                                desc = desc.Replace(string.Format("<<{0}[%d/%d/%d]>>", i + 1), (double.Parse(values[i]) + "*Pts").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d%/%d%/%d%]>>", i + 1), (double.Parse(values[i]) + "*Pts").ToString());
                                desc = desc.Replace(string.Format("<<{0}[$d point/$d point/$d points]>>", i + 1), (double.Parse(values[i]) + "*Pts point(s)").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d additional standard or weak enemies/%d additional standard or weak enemy/%d additional standard or weak enemies]>>", i + 1), (double.Parse(values[i]) + "*Pts additional standard or weak enemies").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d seconds/%d second/%d seconds]>>", i + 1), (double.Parse(values[i]) + "*Pts second(s)").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d stacks/%d stack/%d stacks]>>", i + 1), (double.Parse(values[i]) + "*Pts stack(s)").ToString());
                            }
                            else
                            {
                                desc = desc.Replace(string.Format("<<{0}>>", i + 1), (double.Parse(values[i]) * (double)rank).ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d/%d/%d]>>", i + 1), (double.Parse(values[i]) * (double)rank).ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d%/%d%/%d%]>>", i + 1), (double.Parse(values[i]) * (double)rank).ToString());
                                desc = desc.Replace(string.Format("<<{0}[$d point/$d point/$d points]>>", i + 1), (double.Parse(values[i]) * (double)rank + " point(s)").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d additional standard or weak enemies/%d additional standard or weak enemy/%d additional standard or weak enemies]>>", i + 1), (double.Parse(values[i]) * (double)rank + " additional standard or weak enemies").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d seconds/%d second/%d seconds]>>", i + 1), (double.Parse(values[i]) * (double)rank + " second(s)").ToString());
                                desc = desc.Replace(string.Format("<<{0}[%d stacks/%d stack/%d stacks]>>", i + 1), (double.Parse(values[i]) * (double)rank + " stack(s)").ToString());
                            }
                        }
                    }
                    descs.Add(desc);
                }
                writer.WriteLine("        /// <summary>");
                writer.WriteLine("        /// " + descs[0].Replace("\n", "<br/>\n" + "        /// "));
                writer.WriteLine("        /// </summary>");
                writer.WriteLine("        [TalentData(index: " + currentTalent + ", name: \"" + talent.Ability.Name + "\", maxPoints: "
                                                    + talent.MaxPoints + ", icon: \"" + talent.Ability.Icon + "\",");
                int prereq = -1;
                if (!string.IsNullOrEmpty(talent.Prereq))
                {
                    for (int c = 0; c < tree.Value.Talents.Count; c++)
                    {
                        if (tree.Value.Talents[c].Fqn == talent.Prereq)
                        {
                            prereq = c + treeTalentCountsSaved[currentTree];
                            break;
                        }
                    }
                    if (prereq == -1) { prereq = -2; } // We didn't find it, note as an error with -2 so easy to find later
                }
                writer.WriteLine("         tree: " + currentTree + ", column: " + (talent.Col+1) + ", row: " + (talent.Row+1)
                                        + ", prerequisite: " + prereq + ", description: new[] {");
                for (int rank = 1; rank <= talent.MaxPoints; rank++)
                {
                    writer.WriteLine("        @\"" + descs[rank] + "\",");
                }
                writer.WriteLine("        })]");
                writer.WriteLine("        public int " + talent.Ability.Name.Replace(" ", "").Replace("-", "").Replace(":", "").Replace("'", "").Replace(".", "").Replace("!", "") + " { get { return _data[" + currentTalent + "]; } set { _data[" + currentTalent + "] = value; } }");
                currentTalent++;
                treeTalentCounts[currentTree]++;
                }
                writer.WriteLine("        #endregion // " + tree.Value.Name);
                treeTalentCountsSaved[currentTree] = treeTalentCounts[currentTree];
                currentTree++; 
                }
                writer.WriteLine("    }"); // Close brace from talent class
                writer.WriteLine("    "); // Blank line after each talent tree
                }
                writer.WriteLine("}"); // close brace from namespace
            }
        }
    }
}
